import EventRoute from '../EventRoute'
import { join, resolve } from 'path'
import { writeFile, mkdir, readFile } from 'node:fs/promises'
import { Rejected } from '../type'
import { getDirectory, prettify, useDev, useExportText } from '../utils'
import { existsSync } from 'fs'
import { exec } from 'child_process'
import { setStorage } from '@main/storage'

const routes: EventRoute[] = []

// 生成 Axure 菜单列表
interface DocResp {
  error?: string
  docStr?: string
  isCache?: boolean
}

routes.push(
  new EventRoute('git', async ({ emitToRenderer }, { url, father, id }) => {
    const path = resolve(father as string)

    exec(`cd ${path} && git clone ${url}`, (error, _, stderror) => {
      let errorMessage = ''

      if (error) {
        if (stderror.includes('already exists')) {
          errorMessage = '项目已存在'
        } else {
          errorMessage = stderror
        }
      }

      emitToRenderer({ name: 'git-done', error: errorMessage, id })
    })
  })
)

routes.push(
  new EventRoute('create-doc', async ({ emitToRenderer }, data) => {
    const { url, prefix, suffix, filename, storePath, rewrite } = data

    const emit = (name: string, messages?: DocResp) => emitToRenderer({ name, ...messages })
    const createError = (error: unknown, prefix?: string) => {
      emit('error', { error: `${prefix}出错: ${JSON.stringify(error)}` })
    }

    const directory = resolve(storePath as string, 'records', 'tree')
    const filePath = join(directory, filename as string)
    const docExist = existsSync(filePath)

    emit('fetch-start')

    if (docExist && !rewrite) {
      try {
        const treeStr = await readFile(filePath, { encoding: 'utf-8' })
        emit('create-done', { docStr: treeStr, isCache: true })
      } catch (error) {
        createError(error, `文档已存在，读取`)
      }
      return
    }

    let javascript: string
    try {
      const response = await fetch(url as string)
      javascript = await response.text()
    } catch (error) {
      createError(error, `获取 Axure 文档`)
      return
    }

    emit('fetch-done')

    const start = (prefix as string).length
    const lastIndex = javascript.length - 1
    const end = lastIndex - (suffix as string).length - 1

    let menuTreeText: string
    try {
      const IIFE: string = javascript.slice(start, end)
      menuTreeText = JSON.stringify(eval(IIFE)().sitemap.rootNodes)
    } catch (error) {
      createError(error, `解析 Axure 文档`)
      return
    }

    setTimeout(async () => {
      emit('create-start')

      try {
        await mkdir(directory, { recursive: true })

        await writeFile(filePath, menuTreeText, { encoding: 'utf-8' })

        emit('create-done', { docStr: menuTreeText })
      } catch (error) {
        createError(error, `写入文档`)
        return
      }

      useDev(() => prettify(filePath))
    }, 1000)
  })
)

export let projectRootPath: string
// 选择项目的 views 目录，方便后续自动创建文件夹
routes.push(
  new EventRoute('select-path', async (api, { id }) => {
    const path = await getDirectory(api.dialog, api.mainWindow)
    api.emitToRenderer({ name: 'select-path-done', id, path })
  })
)

// 往 renderer 的 docs 文件夹中写入文件
routes.push(
  new EventRoute('write-file', async ({ emitToRenderer }, { root, filename, content, useExport, id }) => {
    const path = resolve(root as string, filename as string)
    const text = useExportText(content as string, useExport as boolean)

    let message = ''
    try {
      await writeFile(path, text, { encoding: 'utf-8' })

      useDev(() => prettify(path))
    } catch (error: any) {
      message = JSON.stringify(error)
    } finally {
      emitToRenderer({ name: 'write-file-done', error: message, id })
    }
  })
)

// 在指定目录中根据传入的树结构数据创建对应的目录
routes.push(
  new EventRoute('create-directory', async (api, { paths, id, root }) => {
    const results = await Promise.allSettled(
      (paths as string[]).map((subPath) => mkdir(join(root as string, subPath), { recursive: true }))
    )

    const message =
      (results.filter((result) => result.status === 'rejected') as Rejected[])
        .map((failed) => JSON.stringify(failed.reason as string))
        .join('\n') ?? null

    api.emitToRenderer({ name: 'create-directory-done', id, error: message })
  })
)
routes.push(
  new EventRoute('check-is-exist', async ({ emitToRenderer }, { path, returnText, id }) => {
    let content = ''
    let isExist = false

    try {
      isExist = existsSync(path)

      if (returnText) {
        content = await readFile(path, { encoding: 'utf-8' })
        content = content.replace(/^export\sdefault\s/, '')
      }
    } catch (error: any) {
      console.log(error?.message ?? error)
      isExist = false
    }

    emitToRenderer({ name: 'check-is-exist-done', isExist, content, id })
  })
)

routes.push(
  new EventRoute('store-info', async ({ paths }, { id, root }) => {
    await setStorage(id, root)
    paths.updateRoot(id)
  })
)

export default routes.map((route) => route.setType('file'))
